{
 "cells": [
  {
   "cell_type": "markdown",
   "source": [
    "# 千帆function_call工具调用\n",
    "\n",
    "## 简介\n",
    "\n",
    "上一节[千帆function_call入门](./function_call.ipynb)展示了实现chat调用函数的功能，本节将介绍如何让chat与千帆工具进行交互，并编写更便利的调用函数。\n",
    "\n",
    "## 准备\n",
    "\n",
    "本文使用的模块如下：\n",
    "- 千帆 Python SDK中的 chat_completion 模块，该模块提供了与千帆对话引擎的交互接口；\n",
    "- 千帆 tool中的duckduckgo_search_tool，该工具提供了网络搜索功能。"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "a2ef73d1b5366c1d"
  },
  {
   "cell_type": "markdown",
   "source": [
    "首先安装千帆 Python SDK，版本号 >= 0.2.6。"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "f37417f96d78b87e"
  },
  {
   "cell_type": "code",
   "outputs": [],
   "source": [
    "%%capture\n",
    "!pip install \"qianfan>=0.2.6\" -U"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-01-15T06:12:56.960583Z",
     "start_time": "2024-01-15T06:12:54.707741Z"
    }
   },
   "id": "5779c8b36b65d730",
   "execution_count": 104
  },
  {
   "cell_type": "markdown",
   "source": [
    "初始化我们所需要的凭证"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "9e26bd0785ed4ddb"
  },
  {
   "cell_type": "code",
   "outputs": [],
   "source": [
    "# 初始化LLM\n",
    "import os\n",
    "\n",
    "# qianfan sdk 鉴权\n",
    "# os.environ[\"QIANFAN_ACCESS_KEY\"]=\"...\"\n",
    "# os.environ[\"QIANFAN_SECRET_KEY\"]=\"...\"\n"
   ],
   "metadata": {
    "collapsed": true,
    "ExecuteTime": {
     "end_time": "2024-01-15T06:12:56.967249Z",
     "start_time": "2024-01-15T06:12:56.961758Z"
    }
   },
   "id": "initial_id",
   "execution_count": 105
  },
  {
   "cell_type": "markdown",
   "source": [
    "自定义函数库，此处调用qianfan.common.tool中的duckduckgo搜索引擎工具进行搜索，编写today工具查询今天日期。"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "164bd2b4bea750b3"
  },
  {
   "cell_type": "code",
   "outputs": [],
   "source": [
    "from datetime import date\n",
    "from typing import List\n",
    "\n",
    "from qianfan.common.tool.base_tool import BaseTool, ToolParameter\n",
    "from qianfan.common.tool import duckduckgo_search_tool\n",
    "import json\n",
    "\n",
    "\n",
    "class TodayTool(BaseTool):\n",
    "    name: str = \"today\"\n",
    "    description: str = \"获取今天的日期，格式为YYYY-MM-DD\"\n",
    "    parameters: List[ToolParameter] = []\n",
    "\n",
    "    def run(self, parameters: dict = {}) -> dict:\n",
    "        return {\n",
    "            \"date\": date.today().strftime(\"%Y-%m-%d\")\n",
    "        }\n"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-01-15T06:12:56.972779Z",
     "start_time": "2024-01-15T06:12:56.970119Z"
    }
   },
   "id": "938975c875f1941b",
   "execution_count": 106
  },
  {
   "cell_type": "markdown",
   "source": [
    "将工具添加到函数库中并定义函数名映射。"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "598094c5ec2b987c"
  },
  {
   "cell_type": "code",
   "outputs": [],
   "source": [
    "search_tool = duckduckgo_search_tool.DuckDuckGoSearchTool()\n",
    "today_tool = TodayTool()\n",
    "\n",
    "funcs = [\n",
    "    search_tool.to_function_call_schema(),\n",
    "    TodayTool().to_function_call_schema()\n",
    "]\n",
    "\n",
    "func_name_map = {\n",
    "    search_tool.name:search_tool,\n",
    "    today_tool.name:today_tool\n",
    "}"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-01-15T06:12:56.978069Z",
     "start_time": "2024-01-15T06:12:56.974894Z"
    }
   },
   "id": "2368ebd68c4ff812",
   "execution_count": 107
  },
  {
   "cell_type": "markdown",
   "source": [
    "将对话过程封装成函数，方便多轮对话调用"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "42435501fc3cf5af"
  },
  {
   "cell_type": "code",
   "outputs": [],
   "source": [
    "import qianfan\n",
    "\n",
    "def chat(chat_completion, messages, functions, function_map):\n",
    "    resp = chat_completion.do(\n",
    "        messages=messages,\n",
    "        functions=functions\n",
    "    )\n",
    "    \n",
    "    while resp.get(\"function_call\"):\n",
    "        func_call = resp[\"function_call\"]\n",
    "        func_name = func_call[\"name\"]\n",
    "        arguments = json.loads(func_call[\"arguments\"])\n",
    "        func_content_dict = function_map[func_name].run(arguments)\n",
    "        func_content = json.dumps(func_content_dict,ensure_ascii=False)\n",
    "        \n",
    "        messages.append(resp, role=\"assistant\")\n",
    "        messages.append(func_content, role=\"function\")\n",
    "        \n",
    "        resp = chat_completion.do(\n",
    "            messages=messages,\n",
    "            functions=functions\n",
    "        )\n",
    "        \n",
    "        print(\"**call function {}**\".format(func_name))\n",
    "        print(\"function arguments: {}\".format(arguments))\n",
    "        # print(\"function result: {}\".format(func_content))\n",
    "    resp_content = resp[\"result\"]\n",
    "    print(resp_content)\n",
    "    msgs.append(resp_content, role=\"assistant\")"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-01-15T06:12:56.983336Z",
     "start_time": "2024-01-15T06:12:56.980307Z"
    }
   },
   "id": "80a90a0b3061bb21",
   "execution_count": 108
  },
  {
   "cell_type": "markdown",
   "source": [
    "开始对话，首先获取今天的日期。"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "ffb8bb5806b68b85"
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "**call function today**\n",
      "function arguments: {}\n",
      "**No function**\n",
      "根据查询，今天是2024年1月15日。如果您还有其他问题或需要更多信息，请随时告诉我。\n"
     ]
    }
   ],
   "source": [
    "chat_comp = qianfan.ChatCompletion(model=\"ERNIE-Bot-4\")\n",
    "query = \"今天是几号？\"\n",
    "msgs = qianfan.QfMessages()\n",
    "msgs.append(query,role=\"user\")\n",
    "chat(chat_comp, msgs, funcs, func_name_map)"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-01-15T06:13:01.448625Z",
     "start_time": "2024-01-15T06:12:56.984188Z"
    }
   },
   "id": "583538e9f62cb006",
   "execution_count": 109
  },
  {
   "cell_type": "markdown",
   "source": [
    "接下来进行多轮对话，用日期信息来查询新闻。"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "395f9bbe0c5f4f18"
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "**call function duckduckgo_search**\n",
      "function arguments: {'search_query': '新闻 2024-01-14'}\n",
      "**No function**\n",
      "很抱歉，根据我的搜索，没有找到2024年1月14日的新闻标题和摘要。如果您有其他问题或需要进一步帮助，请随时告诉我。\n"
     ]
    }
   ],
   "source": [
    "query = \"那么根据刚才的日期昨天有什么新闻么？搜索并请列举出标题、摘要\"\n",
    "msgs.append(query,role=\"user\")\n",
    "chat(chat_comp, msgs, funcs, func_name_map)"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-01-15T06:13:09.383131Z",
     "start_time": "2024-01-15T06:13:01.452189Z"
    }
   },
   "id": "d924afd4dec1db44",
   "execution_count": 110
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "**No function**\n",
      "除了上述新闻，还有一些其他的新闻，包括：\n",
      "\n",
      "1. 黄晓军院士入选法国国家医学科学院外籍院士：中国工程院院士黄晓军因在骨髓移植领域的开创性工作和杰出成就，入选法国国家医学科学院外籍院士。黄晓军长期致力于白血病等恶性血液疾病的临床和科研工作，勇于突破国际移植禁区，开创了骨髓移植“北京方案”模式，解决了骨髓移植供者来源不足的世界医学难题，大幅提高骨髓移植患者的术后生存率以及生活质量。\n",
      "2. NASA执行“阿耳忒弥斯1号”任务：NASA的太空发射系统和执行“阿耳忒弥斯1号”任务的“猎户座”飞船也是最近的新闻热点。该任务是美国国家航空航天局（NASA）的阿波罗计划以来的首次载人登月任务，计划于2024年将宇航员送往月球南极附近的月球轨道，并开展一系列科学实验和探索活动。\n",
      "3. 京津冀地区发生多起重大事件：在京津冀地区，也发生了多起重大事件，包括北京经开区“火箭街区”飞出“世界之最”等。此外，还有一些社会、经济、文化等方面的新闻，如某公司推出新产品、某明星涉嫌违法等。\n",
      "\n",
      "总之，新闻种类繁多，涵盖了各个领域，人们可以通过各种渠道获取自己感兴趣的新闻信息。\n"
     ]
    }
   ],
   "source": [
    "query = \"还有哪些新闻？\"\n",
    "msgs.append(query,role=\"user\")\n",
    "chat(chat_comp, msgs, funcs, func_name_map)"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-01-15T06:13:31.978941Z",
     "start_time": "2024-01-15T06:13:09.381360Z"
    }
   },
   "id": "bc51c29d5bcbb9be",
   "execution_count": 111
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "**call function duckduckgo_search**\n",
      "function arguments: {'search_query': '新闻主题分类'}\n",
      "**No function**\n",
      "根据您提供的新闻，这些新闻涉及了多个主题，包括医学、航天、社会、经济、文化等。其中，黄晓军院士入选法国国家医学科学院外籍院士的新闻涉及医学领域，NASA执行“阿耳忒弥斯1号”任务的新闻涉及航天领域，京津冀地区发生多起重大事件的新闻涉及社会、经济、文化等多个领域。\n"
     ]
    }
   ],
   "source": [
    "query = \"总结一下，这些新闻涉及了哪些主题？\"\n",
    "msgs.append(query,role=\"user\")\n",
    "chat(chat_comp, msgs, funcs, func_name_map)"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-01-15T06:13:42.110020Z",
     "start_time": "2024-01-15T06:13:31.964383Z"
    }
   },
   "id": "478cde0bb7e87272",
   "execution_count": 112
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
